package org.feng.service.impl;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.AllArgsConstructor;
import org.feng.base.entity.BaseEntity;
import org.feng.entity.Datasource;
import org.feng.entity.Generate;
import org.feng.service.DatasourceService;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 生发代码配置
 *
 * @author feng
 * @since 2021-08-27
 */
@Component
@AllArgsConstructor
public class GenerateAuto {

    private DatasourceService datasourceService;

    private static final String AUTHOR = "Feng";
    private static final String ENTITY = "entity";
    private static final String CONTROLLER = "controller";
    private static final String SERVICE = "service";
    private static final String SERVICE_IMPL = "service.impl";
    private static final String MAPPER = "mapper";
    private static final String XML = "mapper";
    private static final String CONTROLLER_PATH = "templates/controller.java";
    private static final String MAPPER_PATH = "templates/mapper.java";
    private static final String SERVICE_PATH = "templates/service.java";
    private static final String ENTITY_PATH = "templates/entity.java";
    private static final String SERVICE_IMPL_PATH = "templates/serviceImpl.java";
    private static final String MAPPER_XML_PATH = "templates/mapper.xml";
    private static final String VO_FILE_NAME_TAG = "vo";
    private static final String VUE_FILE_NAME_TAG = "vue";
    private static final String JS_FILE_NAME_TAG = "js";

    /**
     * 执行
     */
    public void execute(Generate generate) {
        Datasource datasource = datasourceService.getById(generate.getDatasourceId());
        Map<String, Object> map = new HashMap<>(2);
        map.put("auth", com.feng.utils.NameingUtil.lineToHump(generate.getTableName().replace(generate.getTablePrefix(), "")));
        map.put("entity", generate.getTableName().replace(generate.getTablePrefix(), ""));
        FastAutoGenerator.create(datasource.getUrl(), datasource.getUsername(), datasource.getPassword())
                .globalConfig(builder -> builder.author(AUTHOR)
                        .outputDir(generate.getJavaFile())
                        .disableOpenDir()
                        .dateType(DateType.TIME_PACK))
                .packageConfig(builder -> builder.parent(generate.getParentPath())
                        .moduleName(generate.getModule())
                        .entity(ENTITY)
                        .service(SERVICE)
                        .serviceImpl(SERVICE_IMPL)
                        .mapper(MAPPER)
                        .xml(XML)
                        .controller(CONTROLLER))
                .templateConfig(builder -> builder.disable(TemplateType.ENTITY, TemplateType.SERVICE, TemplateType.SERVICEIMPL, TemplateType.CONTROLLER, TemplateType.MAPPER, TemplateType.XML)
                        .entity(ENTITY_PATH)
                        .service(SERVICE_PATH)
                        .serviceImpl(SERVICE_IMPL_PATH)
                        .mapper(MAPPER_PATH)
                        .controller(CONTROLLER_PATH)
                        .xml(MAPPER_XML_PATH))
                .injectionConfig(builder -> builder.customMap(map)
                        .customFile(getInjectionNameAndPath(generate))
                        .beforeOutputFile((tableInfo, objectMap) -> {
                            TableInfo table = (TableInfo) objectMap.get("table");
                            table.setEntityName(table.getEntityName().replace("Entity", ""));
                            objectMap.put("table", table);
                        }))
                .strategyConfig(builder -> builder.enableSkipView()
                        .enableCapitalMode()
                        .addInclude(generate.getTableName())
                        .addTablePrefix(generate.getTablePrefix())
                        .entityBuilder().superClass(BaseEntity.class)
                        .enableLombok()
                        .enableTableFieldAnnotation()
                        .naming(NamingStrategy.underline_to_camel)
                        .columnNaming(NamingStrategy.underline_to_camel)
                        .idType(IdType.ASSIGN_ID)
                        .formatFileName("%sEntity")
                        .controllerBuilder().enableRestStyle().formatFileName("%sController")
                        .serviceBuilder()
                        .formatServiceFileName("%sService")
                        .formatServiceImplFileName("%sServiceImpl")
                        .mapperBuilder()
                        .superClass(BaseMapper.class)
                        .formatMapperFileName("%sMapper")
                        .formatXmlFileName("%sMapper")).templateEngine(new VelocityTemplateEngine() {
                    //重写自定义模板 保存路径
                    @Override
                    protected void outputCustomFile(Map<String, String> customFile, TableInfo tableInfo, Map<String, Object> objectMap) {
                        String packagePath = generate.getParentPath().replace(".", File.separator) + File.separator + generate.getModule();
                        customFile.forEach((key, value) -> {
                            StringBuilder fileName = new StringBuilder();
                            fileName.append(generate.getJavaFile()).append(File.separator);
                            if (value.contains(VO_FILE_NAME_TAG)) {
                                fileName.append(packagePath).append(File.separator).append(VO_FILE_NAME_TAG).append(File.separator).append(key);
                            }
                            if (value.contains(VUE_FILE_NAME_TAG)) {
                                fileName.append(VUE_FILE_NAME_TAG).append(File.separator).append(key);
                            }
                            if (value.contains(JS_FILE_NAME_TAG)) {
                                fileName.append(JS_FILE_NAME_TAG).append(File.separator).append(key);
                            }
                            outputFile(new File(fileName.toString()), objectMap, value, true);
                        });
                    }
                }).execute();
    }

    /**
     * 获取自定义模板名称和路径
     */
    private Map<String, String> getInjectionNameAndPath(Generate generate) {
        HashMap<String, String> map = new HashMap<>(3);
        String fileName = generate.getTableName().replace(generate.getTablePrefix(), "");
        map.put(com.feng.utils.NameingUtil.lineToHump(fileName) + ".vue", "/templates/vue.vue.vm");
        map.put(com.feng.utils.NameingUtil.lineToHump(fileName) + ".js", "/templates/api.js.vm");
        String voName = com.feng.utils.NameingUtil.lineToHump(fileName);
        voName = voName.substring(0, 1).toUpperCase(Locale.ROOT) + voName.substring(1);
        map.put(voName + "VO.java", "/templates/vo.java.vm");
        return map;
    }
}
